// ValidationAspects
// Written by Mike Saunders
// Released under Microsoft Public License (Ms-PL)
using System;
using NUnit.Framework;
using ValidationAspects;
using ValidationAspects.Core;
using ValidationAspects.Exceptions;
using ValidationAspects.Sdk;

namespace TestValidationAspects.Core
{
	[TestFixture]
	public class TestValidatorAdaptor
	{
		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_constructor_throws_for_null_param()
		{
			new ValidatorAdaptor<Derived, Base>(null);
		}

		[Test]
		public void Test_InvokeT_forwards_invocation()
		{
			BaseValidator baseValidator = new BaseValidator();
			IValidator<Derived> validator = new ValidatorAdaptor<Derived, Base>(baseValidator);

			Derived value = new Derived();
			IValidationContext context = new MockValidationContext();
			validator.Invoke(value, context);

			Assert.AreSame(value, baseValidator.Value);
			Assert.AreSame(context, baseValidator.Context);
		}

		[Test]
		public void Test_Invoke_forwards_invocation()
		{
			BaseValidator baseValidator = new BaseValidator();
			IValidator<Derived> validator = new ValidatorAdaptor<Derived, Base>(baseValidator);

			object value = new Derived();
			IValidationContext context = new MockValidationContext();
			validator.Invoke(value, context);

			Assert.AreSame(value, baseValidator.Value);
			Assert.AreSame(context, baseValidator.Context);
		}

		[Test]
		public void Test_constructor_throws_for_incompatible_types()
		{
			Test.Throws<UnsupportedValidationException>(() => new ValidatorAdaptor<string, Base>(new BaseValidator()),
			                                            string.Format("Failed to cast [type:{0}] to [type:{1}] for validation.", typeof(string), typeof(Base)));
		}

		[Test]
		public void Test_Invoke_for_same_types()
		{
			BaseValidator baseValidator = new BaseValidator();
			IValidator<Base> validator = new ValidatorAdaptor<Base, Base>(baseValidator);

			Base value = new Base();
			IValidationContext context = new MockValidationContext();
			validator.Invoke(value, context);

			Assert.AreSame(value, baseValidator.Value);
			Assert.AreSame(context, baseValidator.Context);
		}

		#region Mocks
		public class Base {}

		public class Derived : Base {}

		public class BaseValidator : IValidator<Base>
		{
			public Base Value { get; set; }
			public IValidationContext Context { get; set; }

			#region Implementation of IValidator
			public void Invoke(Base value, IValidationContext context)
			{
				Value = value;
				Context = context;
			}

			public void Invoke(object value, IValidationContext context)
			{
				throw new NotImplementedException();
			}
			#endregion
		}
		#endregion
	}
}